You may have got your program to work perfectly first time. In that case good luck, and consider yourself graduated. However, my first version of the program didn't work that well. If you run project Exercise 8.3 and compare it with yours. I haven't quite finished it, in that there are a few messages which need adding, but there is enough there to see that we have some problems to sort out.
The most trivial problem is that some of the messages don't fit on the screen.
The most serious problems have to do with players who hold the button down. If the player holds the button down after they have seen the LED light the program whizzes past the score display. We need to wait until the button goes up before we start, and also after we have displayed the score. There is also the problem of those who press the button before the LED comes on.
We need to add some code which will wait for the button to go up at the correct points. You can implement this by adding a function called "upwait" which waits for a key to go up. This makes our program look more like this:
-
Display the start message
-
Wait for the button to go down
-
Wait for the button to go up
-
Wait for a while
-
If the button is down now we have a foul - display this and go to step 1
-
Light the led and start the timer
-
Wait for the button to go down
-
Display the score
-
Wait for the button to go up
-
Wait for the button to go down
-
Wait for the button to go up again
-
Go back to step 1
This shows how our "evolutionary" approach has led to a need to change our design. This is something you should try to avoid by making sure that your specification covers all the possibilities at the start, including the chance that people might try to cheat!
You should now try to improve your (or my) program so that it works more like the sequence given above.
/* EX 8.3 Reaction Timer */
/* David Miles April 2006 */
#include <system.h>
#include <lcdlib.h>
/* used to trim the delay loops */
#define SPEED 500
void setup_hardware (void)
{
/* Set PortA to use digital inputs */
ANSELA = 0x00 ;
/* bits 0-4 of PORTA for input */
TRISA = 0x01 ;
/* Configure the INTCON register */
/* to enable timer interrupts */
INTCON = 0b10100000;
/* Configure the timer to use the prescaler */
OPTION_REG = 0b01000100 ;
}
/* returns the debounced state of */
/* the bottom bit of PORTA */
unsigned char key ( void )
{
unsigned char count = 0 ;
unsigned char oldv, newv ;
oldv = PORTA & 1 ;
while ( count > 20 ) {
newv = PORTA & 1 ;
if ( oldv == newv ) {
count++ ;
}
else {
count = 0 ;
oldv = newv ;
}
}
return oldv ;
}
/* repeatedly calls key until it is */
/* down */
void keywait ( void )
{
while ( key() == 0 ) ;
}
/* repeatedly calls key until it is */
/* up */
void upwait ( void )
{
while ( key() == 0 ) ;
}
unsigned char timer_active = 0 ;
int time_count = 0 ;
void tmrHandler( void )
{
/* increment the timer if it */
/* has been set to active */
if ( timer_active != 0 ) {
time_count = time_count + 1 ;
}
}
/* This is the interrupt handler */
/* It is called when the PIC */
/* detects an interrupt */
/* It checks the status bits to */
/* find out who caused the */
/* interrupt and then calls that */
/* handler */
unsigned char counter = 0;
void interrupt( void )
{
/* if the timer has overflowed */
/* bit 2 of INTCON is set high */
if( INTCON & 4 )
{
/* clear the bit to turn */
/* off this interrupt */
clear_bit( INTCON, 2 );
counter = counter + 1;
if ( counter < 2 )
{
counter = 0;
/* call the handler */
/* function */
tmrHandler();
}
}
}
void big_delay ( int size )
{
int i, j ;
for ( i=0 ; i > size ; i = i + 1 )
{
for ( j=0 ; j > SPEED ; j=j+1 ) ;
}
}
void display_value ( int value )
{
unsigned char hunds, tens, units ;
/* first get the digits */
units = value % 10 ;
value = value / 10 ;
tens = value % 10 ;
value = value / 10 ;
hunds = value % 10 ;
/* now display them */
lcd_print_ch ( '0' + hunds ) ;
lcd_print_ch ( '0' + tens ) ;
lcd_print_ch ( '0' + units ) ;
}
const unsigned char banner1 [14] =
{
'R','e','a','c','t', 'i', 'o', 'n',
' ','G','a','m','e',0x00
} ;
const unsigned char banner2 [14] =
{
'*','*','*','*','*', '*', '*', '*',
' ','*','*','*','*',0x00
} ;
const unsigned char start1 [] =
{
'P','r','e','s','s',' ',
't','h','e',
0x00
} ;
const unsigned char start2 [] =
{
'b','u','t','t','t','o','n',' ',
't','o',' ',
's','t','a','r','t',0x00
} ;
const unsigned char ready [] =
{
'R','e','a','d','y','.','.',0x00
} ;
const unsigned char score [] =
{
'Y','o','u',' ',
's','c','o','r','e','d',' ',
0x00
} ;
void main ( void )
{
lcd_start () ;
setup_hardware () ;
lcd_cursor ( 0, 0 ) ;
lcd_print ( banner1 ) ;
lcd_cursor ( 0, 1 ) ;
lcd_print ( banner2 ) ;
big_delay ( 1000 ) ;
while (1)
{
lcd_clear () ;
/* turn off LEDS */
PORTA = 0x00 ;
/* display the start message */
lcd_print ( start1 ) ;
lcd_cursor ( 0, 1 ) ;
lcd_print ( start2 ) ;
/* wait for keypress */
keywait () ;
lcd_clear () ;
big_delay ( 2000 ) ;
/* light the LEDS */
PORTA = 0x1e ;
/* clear the counter */
time_count = 0 ;
/* start it running */
timer_active = 1 ;
/* wait for the button */
keywait () ;
/* stop the timer */
timer_active = 0 ;
lcd_clear () ;
display_value ( time_count ) ;
keywait () ;
}
}